package fcnet

import (
	"fmt"
	"net"
	"sync/atomic"

	"gitee.com/fcsvr/fancy/fclog"
	"gitee.com/fcsvr/fancy/utils"
)

type Server struct {
	Name      string
	IPVersion string
	IP        string
	Port      int

	cid       uint32
	msgHandle *MsgHandle
	connMgr   *ConnMgr

	OnConnStart func(conn *Conn)
	OnConnStop  func(conn *Conn)
}

var FC_Server *Server

func NewServer(name string) *Server {
	FC_Server = &Server{
		Name:      "FanSvr",
		IPVersion: "tcp4",
		IP:        "0.0.0.0",
		Port:      7000,
		cid:       0,

		msgHandle: NewMsgHandle(),
		connMgr:   NewConnMgr(),
	}
	if err := utils.G_Data.Reload(); err == nil {
		g_data := utils.G_Data
		FC_Server.Name = g_data.Name
		FC_Server.IP = g_data.Host
		FC_Server.Port = g_data.TCPPort
	}
	return FC_Server
}

func (this *Server) Init() error {
	return nil
}

func (this *Server) Serve() {
	fclog.Info("Server Start: listenner at IP: %s, Port %d", this.IP, this.Port)

	go func() {
		this.msgHandle.StartWorkerPool()

		addr, err := net.ResolveTCPAddr(this.IPVersion, fmt.Sprintf("%s:%d", this.IP, this.Port))
		if err != nil {
			fclog.Error("Server Start: resolve tcp addr err = %s", err)
			return
		}
		listenner, err := net.ListenTCP(this.IPVersion, addr)
		if err != nil {
			fclog.Error("Server Start: listen tcp err = %s", err)
			panic("err")
			return
		}
		fclog.Info("Server Start: name = %s start listening", this.Name)

		atomic.AddUint32(&this.cid, 1)
		for {
			tcpconn, err := listenner.AcceptTCP()
			if err != nil {
				fclog.Error("Server Start: accept err = %s", err)
				continue
			}
			if this.connMgr.Len() >= utils.G_Data.MaxConn {
				tcpconn.Close()
				continue
			}
			fclog.Info("Server Start: start a tcpconn id = %d", this.cid)

			dealConn := NewConn(tcpconn, this.cid)
			atomic.AddUint32(&this.cid, 1)
			go dealConn.Start()
		}
	}()
}

func (this *Server) Stop() error {
	fclog.Info("Server Stop: name = %s stop ", this.Name)
	this.connMgr.ClearConn()
	return nil
}

func (this *Server) Start() error {
	this.Serve()

	return nil
}

func (this *Server) AddRouter(msgid uint32, router RouterItf) {
	this.msgHandle.AddRouter(msgid, router)
}

func (this *Server) GetConnMgr() *ConnMgr {
	return this.connMgr
}

func (this *Server) SetOnConnStart(hookFunc func(*Conn)) {
	this.OnConnStart = hookFunc
}

func (this *Server) SetOnConnStop(hookFunc func(*Conn)) {
	this.OnConnStop = hookFunc
}

func (this *Server) CallOnConnStart(conn *Conn) {
	if this.OnConnStart != nil {
		fclog.Info("Server CallOnConnStart")
		this.OnConnStart(conn)
	}
}

func (this *Server) CallOnConnStop(conn *Conn) {
	if this.OnConnStop != nil {
		fclog.Info("Server CallOnConnStop")
		this.OnConnStop(conn)
	}
}

func (this *Server) GetMsgHandle() *MsgHandle {
	return this.msgHandle
}

func (this *Server) PushMsg(msgid uint32, data []byte, connIDs ...uint32) {
	for _, connid := range connIDs {
		conn, err := this.connMgr.Get(connid)
		if err != nil {
			continue
		}
		conn.SendMsg(msgid, data)
	}
}
